package v1

import (
	"easyVolunteer/model"
	"easyVolunteer/utils/code"
	"easyVolunteer/utils/errno"
	"easyVolunteer/utils/excel"
	"easyVolunteer/utils/validate"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/yitter/idgenerator-go/idgen"
	"log"
	"net/http"
	"strconv"
	"time"
)

// CreateActivity 创建新活动
func CreateActivity(c *gin.Context) {
	var activity model.Activity

	_ = c.ShouldBindJSON(&activity)

	activity.Stock = activity.Limits
	// TODO 数据验证
	msg, status := validate.Validate(activity)
	if status != errno.OK {
		c.JSON(http.StatusOK, gin.H{
			"code":   status.Code,
			"msg":    status.Message,
			"detail": msg,
		})
		return
	}

	activity.ActivityID = idgen.NextId() //全局唯一一次调用赋给活动唯一ID
	activity.Status = code.ActivityRecruiting

	status = model.CreateActivity(&activity)

	c.JSON(http.StatusOK, gin.H{
		"code": status.Code,
		"msg":  status.Message,
	})
}

// ChangeActivityStatus 更改活动状态
func ChangeActivityStatus(c *gin.Context) {
	a := struct {
		ID     uint64 `json:"activityID" validate:"required"`
		Status int    ` json:"status" validate:"required"`
	}{}

	err := c.ShouldBindJSON(&a)
	// JSON 绑定，绑定失败直接返回
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": errno.ErrParseParameter.Code,
			"msg":  errno.ErrParseParameter.Message,
		})
		return
	}
	// 数据验证，要求参数是必须的(但是数据长度并不会被验证)
	d1 := model.Digits(a.ID)
	d2 := model.Digits(uint64(a.Status))
	msg, ok := validate.Validate(&a)
	if d1 > code.ActivityIDDigitsNum || d2 > code.ActivityStatusDigitsNum || ok != nil {
		fmt.Println(err)
		c.JSON(http.StatusOK, gin.H{
			"code":   errno.ErrValidateFail.Code,
			"msg":    errno.ErrValidateFail.Message,
			"detail": msg,
		})
		return
	}

	// 传入活动ID 和将要改变的状态
	status := model.ChangeActivityStatus(a.ID, a.Status)

	c.JSON(http.StatusOK, gin.H{
		"code": status.Code,
		"msg":  status.Message,
	})
}

// CancelActivity 取消活动
func CancelActivity(c *gin.Context) {
	activityID, err := strconv.Atoi(c.Query("activityID"))
	if err != nil {
		log.Println("取消活动失败")
		c.JSON(http.StatusOK, gin.H{
			"code": errno.ErrParseParameter.Code,
			"msg":  errno.ErrParseParameter.Message,
		})
		return
	}

	status := model.ChangeActivityStatus(uint64(activityID), code.ActivityCancel)

	c.JSON(http.StatusOK, gin.H{
		"code": status.Code,
		"msg":  status.Message,
	})
}

// StopActivityRecruit 停止活动招募
func StopActivityRecruit(c *gin.Context) {
	activityID, err := strconv.Atoi(c.Query("activityID"))
	if err != nil {
		log.Println("停止活动招募")
		c.JSON(http.StatusOK, gin.H{
			"code": errno.ErrParseParameter.Code,
			"msg":  errno.ErrParseParameter.Message,
		})
		return
	}

	// 一旦停止招募，直接进入活动进行中状态
	status := model.ChangeActivityStatus(uint64(activityID), code.ActivityRunning)

	c.JSON(http.StatusOK, gin.H{
		"code": status.Code,
		"msg":  status.Message,
	})
}

func ActivityFinished(c *gin.Context) {
	activityID, err := strconv.Atoi(c.Query("activityID"))
	if err != nil {
		log.Println("更改活动完成状态失败")
		c.JSON(http.StatusOK, gin.H{
			"code": errno.ErrParseParameter.Code,
			"msg":  errno.ErrParseParameter.Message,
		})
		return
	}

	status := model.FinishActivity(uint64(activityID))
	c.JSON(http.StatusOK, gin.H{
		"code": status.Code,
		"msg":  status.Message,
	})
}

// GetActivityInfo 获取某一个活动的具体信息
func GetActivityInfo(c *gin.Context) {
	activityID, err := strconv.Atoi(c.Query("activityID"))
	if err != nil {
		log.Println("参数解析失败")
		c.JSON(http.StatusOK, gin.H{
			"code": errno.ErrParseParameter.Code,
			"msg":  errno.ErrParseParameter.Message,
		})
		return
	}
	exist := model.CheckActivityExist(uint64(activityID))
	if !exist {
		c.JSON(http.StatusOK, gin.H{
			"code":    errno.ErrActivityNotExist.Code,
			"message": errno.ErrActivityNotExist.Message,
		})
		return
	}
	activity, status := model.FindActivityInfo(uint64(activityID), "status", "limit", "stock", "duration", "rang", "start_time", "end_time")

	c.JSON(http.StatusOK, gin.H{
		"activity": activity,
		"code":     status.Code,
		"msg":      status.Message,
	})
}

// GetActivityList 获取活动列表 (默认为正在招募的)
func GetActivityList(c *gin.Context) {
	var (
		pageNum  = 1
		pageSize = 20
		status   = code.ActivityRecruiting
		err      error
	)
	pageNum, err = strconv.Atoi(c.DefaultQuery("pageNum", "1"))
	pageSize, err = strconv.Atoi(c.DefaultQuery("pageSize", "20"))
	status, err = strconv.Atoi(c.DefaultQuery("status", "1001"))

	if err != nil {
		log.Println("参数解析失败")
		c.JSON(http.StatusOK, gin.H{
			"code": errno.ErrParseParameter.Code,
			"msg":  errno.ErrParseParameter.Message,
		})
		return
	}

	a, r := model.GetActivities(pageNum, pageSize, status)

	c.JSON(http.StatusOK, gin.H{
		"code":       r.Code,
		"msg":        r.Message,
		"length":     len(a),
		"activities": a,
	})
}

// GetAllOwnedActivity 获取某人创建的所有的活动
func GetAllOwnedActivity(c *gin.Context) {
	userID := c.Query("userID")

	if len(userID) != 10 {
		log.Println("参数解析失败")
		c.JSON(http.StatusOK, gin.H{
			"code": errno.ErrParseParameter.Code,
			"msg":  errno.ErrParseParameter.Message,
		})
		return
	}
	activities, status := model.AllOwnedActivity(userID)
	c.JSON(http.StatusOK, gin.H{
		"code":       status.Code,
		"msg":        status.Message,
		"length":     len(activities),
		"activities": activities,
	})
}

// GetAllVolunteer 获取参加活动的所有志愿者
func GetAllVolunteer(c *gin.Context) {
	activityID, err := strconv.Atoi(c.Query("activityID"))
	if err != nil {
		log.Println("获取参加活动的所有志愿者失败，err:", err)
		c.JSON(http.StatusOK, gin.H{
			"code": errno.InternalServerError.Code,
			"msg":  errno.InternalServerError.Message,
		})
		return
	}
	users, status := model.GetVolunteers(uint64(activityID))
	c.JSON(http.StatusOK, gin.H{
		"code":  status.Code,
		"msg":   status.Message,
		"users": users,
		"size":  len(users),
	})
}

func ActivityCount(c *gin.Context) {
	var a model.Activity
	c.ShouldBindJSON(&a)

	count, err := model.Count(a)

	c.JSON(http.StatusOK, gin.H{
		"code":  err.Code,
		"msg":   err.Message,
		"count": count,
	})
}

func ActivitySummary(c *gin.Context) {
	pageSize, _ := strconv.Atoi(c.Query("pageSize"))
	pageNum, _ := strconv.Atoi(c.Query("pageNum"))

	type Q struct {
		Start       string `json:"start"`
		End         string `json:"end"`
		GeneralCode string `json:"generalCode"`
		Export      string `json:"export"`
	}
	var q Q
	c.ShouldBindJSON(&q)

	_, err := time.Parse("2006-01-02", q.Start)
	_, err = time.Parse("2006-01-02", q.End)
	if err != nil {
		c.JSON(http.StatusOK, gin.H{
			"code": errno.ErrValidateFail.Code,
			"msg":  errno.ErrValidateFail.Message,
		})
		return
	}

	if len(q.GeneralCode) <= 2 {
		c.JSON(http.StatusOK, gin.H{
			"code": errno.ErrValidateFail.Code,
			"msg":  errno.ErrValidateFail.Message,
		})
		return
	}
	if q.Export == "True" {
		pageSize, pageNum = -1, -1 //通过 -1 消除 Limit 和 Offset 条件
	}
	u, err1 := model.CalculateSummaryData(q.GeneralCode, q.Start, q.End, pageNum, pageSize)

	if q.Export == "True" {
		url, r := excel.WriteExcel(u)
		c.JSON(http.StatusOK, gin.H{
			"code": r.Code,
			"msg":  r.Message,
			"url":  url,
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code": err1.Code,
		"msg":  err1.Message,
		"user": u,
	})
}
